package com.kexilo.system.auth.service;

import com.kexilo.core.common.constant.Constants;
import com.kexilo.core.common.exception.ServiceException;
import com.kexilo.core.common.utils.IpUtils;
import com.kexilo.core.common.utils.ServletUtils;
import com.kexilo.core.common.utils.StringUtils;
import com.kexilo.core.security.domain.LoginUser;
import com.kexilo.core.security.service.TokenService;
import com.kexilo.core.common.service.OperationLogService;
import com.kexilo.system.auth.service.CaptchaService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import jakarta.servlet.http.HttpServletRequest;

/**
 * 登录校验方法
 * 
 * @author Kexilo
 */
@Component
public class SysLoginService {

    private static final Logger log = LoggerFactory.getLogger(SysLoginService.class);

    @Autowired
    private TokenService tokenService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private CaptchaService captchaService;
    
    @Autowired
    private OperationLogService operationLogService;

    /**
     * 登录验证
     * 
     * @param username 用户名
     * @param password 密码
     * @param captcha 验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    public String login(String username, String password, String captcha, String uuid) {
        // 验证码校验
        validateCaptcha(username, captcha, uuid);
        
        // 登录前置校验
        loginPreCheck(username, password);
        
        // 用户验证
        Authentication authentication = null;
        try {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                // TODO: 记录登录失败日志
                recordLoginInfo(username, Constants.LOGIN_FAIL, "用户不存在/密码错误");
                throw new ServiceException("用户不存在/密码错误");
            } else {
                // TODO: 记录登录失败日志
                recordLoginInfo(username, Constants.LOGIN_FAIL, e.getMessage());
                throw new ServiceException(e.getMessage());
            }
        } finally {
            // TODO: 发布登录尝试事件
            // publishLoginAttempt(username, IpUtils.getIpAddr(), authentication != null);
        }
        
        // TODO: 记录登录成功日志
        recordLoginInfo(username, Constants.LOGIN_SUCCESS, "登录成功");
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        
        // 生成token
        return tokenService.createToken(loginUser);
    }

    /**
     * 校验验证码
     * 
     * @param username 用户名
     * @param captcha 验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    public void validateCaptcha(String username, String captcha, String uuid) {
        if (StringUtils.isEmpty(captcha) || StringUtils.isEmpty(uuid)) {
            recordLoginInfo(username, Constants.LOGIN_FAIL, "验证码不能为空");
            throw new ServiceException("验证码不能为空");
        }
        
        try {
            // 使用验证码服务进行验证
            boolean isValid = captchaService.validateCaptcha(uuid, captcha);
            
            if (!isValid) {
                recordLoginInfo(username, Constants.LOGIN_FAIL, "验证码错误");
                throw new ServiceException("验证码错误");
            }
            
            log.debug("验证码校验成功: username={}, captcha={}, uuid={}", username, captcha, uuid);
            
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            log.error("验证码校验异常: username={}, error={}", username, e.getMessage(), e);
            recordLoginInfo(username, Constants.LOGIN_FAIL, "验证码校验失败");
            throw new ServiceException("验证码校验失败");
        }
    }

    /**
     * 登录前置校验
     * @param username 用户名
     * @param password 用户密码
     */
    public void loginPreCheck(String username, String password) {
        // 用户名或密码为空 错误
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            recordLoginInfo(username, Constants.LOGIN_FAIL, "用户名/密码不能为空");
            throw new ServiceException("用户名/密码不能为空");
        }
        
        // 密码如果不在指定范围内 错误
        if (password.length() < 5 || password.length() > 20) {
            recordLoginInfo(username, Constants.LOGIN_FAIL, "用户密码不在指定范围");
            throw new ServiceException("用户密码不在指定范围");
        }
        
        // 用户名不在指定范围内 错误
        if (username.length() < 2 || username.length() > 20) {
            recordLoginInfo(username, Constants.LOGIN_FAIL, "用户名不在指定范围");
            throw new ServiceException("用户名不在指定范围");
        }
        
        // IP黑名单校验
        String blackStr = "127.0.0.2"; // 示例黑名单IP
        if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) {
            recordLoginInfo(username, Constants.LOGIN_FAIL, "很遗憾，访问IP已被列入系统黑名单");
            throw new ServiceException("很遗憾，访问IP已被列入系统黑名单");
        }
    }

    /**
     * 记录登录信息
     * 
     * @param username 用户名
     * @param status 状态
     * @param message 消息
     */
    public void recordLoginInfo(String username, String status, String message) {
        try {
            String ipAddr = IpUtils.getIpAddr();
            String location = IpUtils.getRealAddressByIP(ipAddr);
            String browser = ServletUtils.getBrowser();
            String os = ServletUtils.getOs();
            
            // 简化架构：直接调用日志服务保存到数据库，无需复杂的Event系统
            operationLogService.saveLoginLog(username, status, ipAddr, location, browser, os, message);
            
            log.info("登录日志: username={}, status={}, message={}, ip={}, location={}, browser={}, os={}", 
                    username, status, message, ipAddr, location, browser, os);
                    
        } catch (Exception e) {
            log.error("记录登录日志异常: username={}, error={}", username, e.getMessage(), e);
        }
    }

    /**
     * 退出登录
     * 
     * @param loginUser 登录用户信息
     */
    public void logout(LoginUser loginUser) {
        if (StringUtils.isNotNull(loginUser)) {
            String userName = loginUser.getUsername();
            // 删除用户缓存记录
            tokenService.delLoginUser(loginUser.getToken());
            // 记录用户退出日志
            recordLoginInfo(userName, Constants.LOGOUT, "退出成功");
        }
    }
}
